package controller;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;

import model.Gamefield;
import model.menupages.Gamepage;
import model.menupages.Hauptmenu;
import view.Master;
import view.menuelements.MenuLabel;
import view.steine.Spielblock;
import view.steine.Spielblock_blau;
import view.steine.Spielblock_cyan;
import view.steine.Spielblock_gelb;
import view.steine.Spielblock_gruen;
import view.steine.Spielblock_orange;
import view.steine.Spielblock_rot;
import view.steine.Spielblock_violett;
import view.steine.Standardblock;

public class Gamefieldcontroller {

	private static Gamepage gamepage;
	private static Gamecontroller gamecontroller;
	private static Highscorecontroller highscorecontroller = new Highscorecontroller();
	private static Timer t;
	private Random rnd = new Random();
	private Spielblock spielblockarray[] = new Spielblock[7];
	public Spielblock aktiverSpielblock;
	private Spielblock nextSpielblock;
	private Spielblock nextnextSpielblock;
	private Standardblock vorhandeneSpielsteine[][] = new Standardblock[Gamefield
			.getBreite()][Gamefield.getHoehe()];
	private static int delay;
	public static boolean speed;

	public Gamefieldcontroller(Gamepage gamepage) {
		this.gamepage = gamepage;
		gamecontroller = new Gamecontroller();
		loadAllStones();
		neuerStein();

		// init vom Timer
		t = new Timer(500, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				doOnTick();
			}
		});
		t.start();
	}

	// in dieser Methode werden alle Steine geladen
	private void loadAllStones() {

		// in ein Array von Spielobjekten zusammengeführt.

		spielblockarray[0] = new Spielblock_blau(new Standardblock(
				"Standardblock.png"));
		spielblockarray[1] = new Spielblock_cyan(new Standardblock(
				"Standardblock_1.png"));
		 spielblockarray[2] = new Spielblock_rot(new Standardblock(
				 "Standardblock_2.png"));
		 spielblockarray[3] = new Spielblock_orange(new Standardblock(
				 "Standardblock_3.png")); 
		 spielblockarray[4] = new Spielblock_violett(new Standardblock( 
				 "Standardblock_4.png"));
		 spielblockarray[5] = new Spielblock_gruen(new Standardblock(
				 "Standardblock_5.png")); 
		 spielblockarray[6] = new Spielblock_gelb(new Standardblock( 
				 "Standardblock_6.png"));

		// laedt die ersten 3 Steine
		aktiverSpielblock = spielblockarray[rnd.nextInt(7)];
		nextSpielblock = spielblockarray[rnd.nextInt(7)];
		nextnextSpielblock = spielblockarray[rnd.nextInt(7)];
	}

	// hier wird die Geschwindigkeit beim Level up angepasst
	// aktuell wird der Delay mit dem Faktor 0,825 verkuerzt
	public static void lvlup() {
		t.setDelay((t.getDelay() * 7) / 8);
		gamepage.level.setText("<html>Level:<br>" + gamecontroller.getLevel()
				+ "</html>");
	}

	// erhaelt die Ereignisse vom Tickerlistener
	public void doOnTick() {
		// checkt ob Steine sich beruehren
		// true bei "freier Bahn"
		if (aktiverSpielblock.doChecks(vorhandeneSpielsteine, Spielblock.DOWN) == true) {
			// Spielstein faellt
			aktiverSpielblock.setNewPos(gamepage, vorhandeneSpielsteine,
					Spielblock.DOWN);
		} else {
			stoneLanded();
			aktiverSpielblock = nextSpielblock;
			nextSpielblock = nextnextSpielblock;
			nextnextSpielblock = spielblockarray[rnd.nextInt(7)];
			neuerStein();
		}
	}

	private void neuerStein() {

		aktiverSpielblock.setPos(new Point(4, 20));
		aktiverSpielblock.setInArray(vorhandeneSpielsteine);
		aktiverSpielblock.show(gamepage);

	}

	// regelt den Ablauf beim landen eines Steins
	private void stoneLanded() {
		// Punkte
		gamecontroller.addScore(1);

		// Ueberpruefung ob Reihe zerstoert
		int row = 0;
		int niedrigstezerstoerteReihe = 0;
		int counter;
		for (int j = 0; j < Gamefield.getHoehe(); j++) {
			counter = 0;
			for (int i = 0; i < Gamefield.getBreite(); i++) {
				if (vorhandeneSpielsteine[i][j] == null) {
					break;
				} else {
					counter++;
				}
			}
			if (counter == Gamefield.getBreite()) {
				row++;
				niedrigstezerstoerteReihe = j;
			}
		}
		if (row > 0) {
			rowdestroyed(row, niedrigstezerstoerteReihe - row + 1);
		}

		// setzen der neuen Hoehe;
		else {
			int max = gamecontroller.getHoehe();
			for (int i = 0; i < Gamefield.getBreite(); i++) {
				if (vorhandeneSpielsteine[i][max] != null) {
					max++;
					i = 0;
					if (max == 20) {
						break;
					}
				}
			}

			gamecontroller.setHoehe(max);
			if (max == gamecontroller.getMaxhoehe()) {
				gamepage.repaint();
				gamepage.validate();
				max = 0;
				gamelost();

			}
		}
	}

	// regelt den Ablauf beim Zerstoeren einer Reihe
	public void rowdestroyed(int anzahl, int reihennr) {
		int score = 0;

		// legt fest wie viele Punkte pro Reihe erhalten werden.
		switch (anzahl) {
		case 1:
			score = 5;
			break;
		case 2:
			score = 12;
			break;
		case 3:
			score = 21;
			break;
		case 4:
			score = 32;
			break;
		}

		gamecontroller.addScore(score);
		gamecontroller.addRows(anzahl);
		gamecontroller.setHoehe(gamecontroller.getHoehe() - anzahl);
		gamepage.rows.setText("<html>Rows: <br>" + gamecontroller.getRows()
				+ "</html>");

		// iteriert durch das Array und setzt jeden Spielstein nach unten und
		// ergaenzt die obere Reihe mit einem null
		for (int p = 0; p < anzahl; p++) {
			for (int i = 0; i < Gamefield.getBreite(); i++) {
				for (int k = reihennr; k < Gamefield.getHoehe(); k++) {
					if (k == Gamefield.getHoehe() - 1) {
						vorhandeneSpielsteine[i][k] = null;
					} else {
						vorhandeneSpielsteine[i][k] = vorhandeneSpielsteine[i][k + 1];
					}
				}
			}
		}

		gamepage.deleteAllStones();
		gamepage.drawAllStones(vorhandeneSpielsteine);

	}

	// regelt den Ablauf beim Verlieren des Spiels
	public void gamelost() {
		t.stop();
		Hauptmenu hauptmenu = new Hauptmenu();
		hauptmenu.setVisible(false);
		String name = "" + JOptionPane.showInputDialog("Whats ur motherfu***ng name?");
		if (name.length() == 0) {
			name = "Anonymous";
		}
		// vergleiche mit highscore
		highscorecontroller.addHighscore(name, gamecontroller.getScore());

		// Loeschen der instanzen fuer naechstes Spiel
		gamecontroller = null;
		t = null;
		System.runFinalization();
		System.gc();
		hauptmenu.setVisible(true);
		Master.setPageInvisible(gamepage);
	}

	public Standardblock[][] getVorhandeneSpielsteine() {
		return vorhandeneSpielsteine;
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
	}

	public static void pause() {
		t.stop();
	}

	public static void unpause() {
		t.start();
		gamepage.requestFocus();

	}

	public void drehen() {
		if (aktiverSpielblock.checkTurn(vorhandeneSpielsteine)) {
			aktiverSpielblock.delOutOfArray(vorhandeneSpielsteine);
			aktiverSpielblock.remove(gamepage);
			aktiverSpielblock.drehen();
			aktiverSpielblock.setInArray(vorhandeneSpielsteine);
			aktiverSpielblock.show(gamepage);
		}
	}

	public static void speedUp() {
		speed = true;
		delay = t.getDelay();
		t.setDelay(40);
	}

	public static void slowDown() {
		speed= false;
		t.setDelay(delay);
	}

}
